package com.item.manager.repository;

import com.google.common.collect.Range;
import com.item.manager.*;
import com.item.manager.serialize.*;

import java.util.List;
import java.util.function.Function;

import static java.lang.String.format;
import static java.util.stream.Collectors.toList;

/**
 * Perform transformation between Adaptor and actual template;
 *
 * Created by Alexey on 3/4/2015.
 */
public class TemplateFunction implements Function<TemplateAdaptor, Template> {


    public Template apply(TemplateAdaptor a) {
        ImmutableTemplate.Builder builder = ImmutableTemplate.builder();
        builder.name(a.getName()).addAllTags(a.getTags().stream().map(ImmutableTag::of).collect(toList()));
        builder.addAllAttributes(a.getAttributes().stream().map(this::fromAdapter).collect(toList()));

        List<Template> mixins = a.getMixins().stream().map(this::apply).collect(toList());

        return builder.build();
    }

    private Attribute fromAdapter(AttributeAdaptor a) {
        if (a instanceof FlagAttributeAdaptor) {
            return ImmutableFlagAttribute.builder().name(a.getName()).
                    value(((FlagAttributeAdaptor) a).getValue()).build();
        } else if (a instanceof NumberAttributeAdaptor) {
            return ImmutableIntAttribute.builder().name(a.getName()).
                    value(((NumberAttributeAdaptor) a).getValue()).build();
        } else if (a instanceof StringAttributeAdaptor) {
            return ImmutableStringAttribute.builder().name(a.getName()).
                    value(((StringAttributeAdaptor) a).getValue()).build();
        } else if (a instanceof RangeAttributeAdapter) {
            return ImmutableRangeAttribute.builder().name(a.getName()).
                    value(parse(((RangeAttributeAdapter) a).getValue())).build();
        }
        throw new RuntimeException(format("No suitable value found for %s", a));
    }

    private Range<Integer> parse(String val) {
        String[] result = val.split("-");
        return Range.closed(Integer.valueOf(result[0].trim()), Integer.valueOf(result[1].trim()));
    }
}
